// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "PacketManager.h"
#include "Include/msghead.h"
#include "MemoryManagement/VmiBuffer.h"
#include "Log/logging.h"

using namespace std;

std::mutex PacketManager::g_mutex = {};
PacketManager *PacketManager::g_instance = nullptr;

/*
 * @功能描述：获得PacketManager单例
 * @返回值：PacketManager单例
 */
PacketManager* PacketManager::GetInstance()
{
    std::lock_guard<std::mutex> lock(g_mutex);
    if (g_instance == nullptr) {
        g_instance = new (std::nothrow) PacketManager();
        if (g_instance == nullptr) {
            ERR("error: failed to create packet manager");
        }
    }
    return g_instance;
}

/*
 * @功能描述：销毁PacketManager单例
 */
void PacketManager::CloseInstance()
{
    std::lock_guard<std::mutex> lock(g_mutex);
    if (g_instance != nullptr) {
        delete g_instance;
        g_instance = nullptr;
    }
}

/*
 * @功能描述：构造函数，初始化包队列数组为空
 */
PacketManager::PacketManager()
{
    m_packetQueues.fill(nullptr);
}

/*
 * @功能描述：析构函数，销毁数据包队列
 */
PacketManager::~PacketManager()
{
    m_packetQueues.fill(nullptr);
}

/*
 * @功能描述：验证数据包队列类型和对应的数据包队列是否存在
 * @参数 [in] type：数据包队列类型
 * @返回值：类型合法且数据包队列存在返回true，否则返回false
 */
bool PacketManager::Verify(VMIMsgType type)
{
    if (type <= VMIMsgType::Invalid || type >= VMIMsgType::End) {
        ERR("error: invalid msg type: %u", type);
        return false;
    }
    if (m_packetQueues[type] == nullptr) {
        ERR("error: packet queue:%u is nullptr", type);
        return false;
    }
    return true;
}

/*
 * @功能描述：创建指定类型的数据包队列，不加锁，不支持在多线程情况下创建和删除队列
 * @参数 [in] type：数据包类型
 * @参数 [in] isBlock：是否阻塞
 * @返回值：成功返回true，失败返回false
 */
bool PacketManager::CreateQueue(VMIMsgType type, bool isBlock)
{
    // 验证msg type
    if (type <= VMIMsgType::Invalid || type >= VMIMsgType::End) {
        ERR("error: invalid msg type: %u", type);
        return false;
    }

    std::shared_ptr<PacketQueue> queue(new (std::nothrow) PacketQueue(false, false, isBlock));
    if (queue == nullptr) {
        ERR("error: failed to create packet queue, type:%u", type);
        return false;
    }

    INFO("packet queue created, type:%u, block:%d", type, isBlock);
    m_packetQueues[type] = queue;
    return true;
}

/*
 * @功能描述：把数据包加入指定类型的队列
 * @参数 [in] type：数据包类型
 * @参数 [in] packet：数据包的地址和大小
 * @返回值：成功返回true，失败返回false
 */
bool PacketManager::PutPkt(VMIMsgType type, const std::pair<uint8_t *, uint32_t> &packet)
{
    if (!Verify(type)) {
        ERR("error: PutPkt failed");
        VmiFreeBuffer(packet.first); // msg类型非法或队列为空，释放数据包，VmiFreeBuffer会对buffer判空
        return false;
    }

    m_packetQueues[type]->PutPkt(packet);
    return true;
}

/*
 * @功能描述：从指定数据包队列中取出包
 * @参数 [in] data：数据地址
 * @参数 [in] length：数据大小
 * @返回值：验证参数非法返回空pair，有数据包返回其地址和大小，没有数据包，阻塞模式下等待，非阻塞模式返回空pair
 */
std::pair<uint8_t *, uint32_t> PacketManager::GetNextPkt(VMIMsgType type)
{
    if (!Verify(type)) {
        ERR("error: GetNextPkt failed");
        return std::pair<uint8_t *, uint32_t>(nullptr, 0);
    }
    return m_packetQueues[type]->GetNextPkt();
}

/*
 * @功能描述：清空所有数据包队列
 */
void PacketManager::ClearPkt()
{
    for (auto &queue : m_packetQueues) {//lint !e1072
        if (queue != nullptr) {
            queue->Clear();
        }
    }
}//lint !e681

/*
 * @功能描述：清空指定类型的数据包队列
 * @参数 [in] type：数据包队列的类型
 */
void PacketManager::ClearQueue(VMIMsgType type)
{
    if (!Verify(type)) {
        ERR("error: ClearQueue failed");
        return;
    }
    m_packetQueues[type]->Clear();
}

/*
 * @功能描述：撤销指定类型的数据包队列
 * @参数 [in] type：数据包队列的类型
 */
void PacketManager::Cancel(VMIMsgType type)
{
    if (!Verify(type)) {
        ERR("error: Cancel failed");
        return;
    }
    m_packetQueues[type]->Cancel();
}

/*
 * @功能描述：恢复指定类型的数据包队列
 * @参数 [in] type：数据包队列类型
 */
void PacketManager::Continue(VMIMsgType type)
{
    if (!Verify(type)) {
        ERR("error: Continue failed");
        return;
    }
    m_packetQueues[type]->Continue();
}